package com.mklimek.frameviedoview;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;

import com.common.base.log.DLog;
import com.photoeditor.demo.model.image.ZoomAttacher;

public @TargetApi(14)
class TextureViewImpl extends TextureView implements
        Impl,
        MediaPlayer.OnPreparedListener,
        TextureView.SurfaceTextureListener,
        MediaPlayer.OnBufferingUpdateListener {

    private View placeholderView;
    private Uri videoUri;
    private boolean supportZoom;
    private FrameVideoViewListener listener;

    private Surface surface;
    private MediaPlayer mediaPlayer;
    private boolean prepared;
    private boolean startInPrepare;
    private boolean prepareAfterTextAvailable;
    private boolean textAvailable;
    private int videoWidth;
    private int videoHeight;
    private boolean hasContent;
    private ZoomAttacher zoomAttacher;

    public TextureViewImpl(Context context) {
        super(context);
    }

    public TextureViewImpl(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void init(View placeholderView, Uri videoUri, boolean supportZoom) {
        this.placeholderView = placeholderView;
        this.videoUri = videoUri;
        this.supportZoom = supportZoom;
        setSurfaceTextureListener(this);
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
//        LOG.trace("onPrepared isPlaying={}", mp.isPlaying());
        if(listener != null){
            listener.mediaPlayerPrepared(mp);
        }
        mp.setLooping(true);
        if(startInPrepare){
            mp.start();
            startInPrepare = false;
        }
        prepared = true;
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
//        LOG.trace("onSurfaceTextureAvailable resource={}", videoUri);
        this.surface = new Surface(surface);
        if (prepareAfterTextAvailable) {
            prepare();
        }
        textAvailable = true;
    }

    private void prepare() {
        try {
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setDataSource(getContext(), videoUri);
            mediaPlayer.setSurface(surface);
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.setOnInfoListener(new InfoListener(placeholderView));
            mediaPlayer.setOnBufferingUpdateListener(this);
            mediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
                @Override
                public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
//                    updateTextureViewSize(width, height);
                    videoWidth = width;
                    videoHeight = height;
                    if (!hasContent) {
                        hasContent = true;
                        if (supportZoom) {
                            zoomAttacher = new ZoomAttacher(TextureViewImpl.this);
                            zoomAttacher.setOnViewTapListener(new ZoomAttacher.OnViewTapListener() {
                                @Override
                                public void onViewTap(View view, float x, float y) {
                                    if (listener != null) {
                                        listener.onViewTap(view, x, y);
                                    }
                                }
                            });
                            zoomAttacher.setMaximumScale(12.0f);
                            zoomAttacher.setMediumScale(1.0f);
                        }
                    } else {
                        if (zoomAttacher != null) {
                            zoomAttacher.update();
                        }
                    }
                }
            });
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            DLog.e("cannot prepare media player with SurfaceTexture", e.getMessage());
        }
    }

    private void updateTextureViewSize(int videoWidth, int videoHeight) {
        float viewWidth = getWidth();
        float viewHeight = getHeight();

        float viewRatio = viewWidth / viewHeight;
        float videoRatio = (float)videoWidth / videoHeight;

        float scaleX = 1.0f;
        float scaleY = 1.0f;

        if (viewRatio < videoRatio) {
            scaleY =  (viewWidth / videoRatio) / viewHeight;
        } else {
            scaleX = (viewHeight * videoRatio) / viewWidth;
        }

        // Calculate pivot points, in our case crop from center
        int pivotPointX;
        int pivotPointY;

        pivotPointX = (int) (viewWidth / 2);
        pivotPointY = (int) (viewHeight / 2);

        Matrix matrix = new Matrix();
        matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY);

        setTransform(matrix);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        textAvailable = false;
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }

    @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
//        LOG.trace("onBufferingUpdate percent {}", percent);
    }

    @Override
    public void onResume() {
//        if(prepared) {
////            LOG.trace("start video");
//            mediaPlayer.start();
//        } else{
//            startInPrepare = true;
//        }
        start();

        if(isAvailable()){
            onSurfaceTextureAvailable(getSurfaceTexture(), 0, 0);
        }
    }

    @Override
    public void onPause() {
        pause();
    }

    @Override
    public void setFrameVideoViewListener(FrameVideoViewListener listener) {
        this.listener = listener;
    }

    @Override
    public void start() {
        if (mediaPlayer == null) {
            startInPrepare = true;
            if (textAvailable) {
                prepare();
            } else {
                prepareAfterTextAvailable = true;
            }
        } else if(prepared) {
            mediaPlayer.start();
        } else{
            startInPrepare = true;
        }
    }

    @Override
    public void pause() {
//        startInPrepare = false;
//        if(mediaPlayer != null && mediaPlayer.isPlaying()) {
//            mediaPlayer.pause();
//        }
        placeholderView.setVisibility(View.VISIBLE);
        if(mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
        mediaPlayer = null;
        prepared = false;
        startInPrepare = false;
        prepareAfterTextAvailable = false;
        if (zoomAttacher != null) {
            zoomAttacher.update();
        }
    }

    @Override
    public void stop() {
        placeholderView.setVisibility(View.VISIBLE);
        if(mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
        mediaPlayer = null;
        prepared = false;
        startInPrepare = false;
        prepareAfterTextAvailable = false;
        if (zoomAttacher != null) {
            zoomAttacher.update();
        }
    }

    @Override
    public View getView() {
        return this;
    }

    @Override
    public void setMatrix(Matrix matrix) {
        setTransform(matrix);
    }

    @Override
    public int getContentWidth() {
        return videoWidth;
    }

    @Override
    public int getContentHeight() {
        return videoHeight;
    }

    @Override
    public boolean hasContent() {
        return hasContent;
    }

}
